/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * DragBarPanel.java
 *
 * Created on May 11, 2009, 3:40:42 PM
 */
package DragBarPanelPackage;

import java.awt.Dimension;
import java.awt.Font;
import java.awt.Point;
import java.util.Vector;
import javax.swing.JButton;

/**
 *
 * @author Evan
 */
public class DragBarPanel extends javax.swing.JPanel
{

  /** Creates new form DragBarPanel */
  public DragBarPanel()
  {
    initComponents();
  }

  public DragBarPanel(int numButtons)
  {
    initComponents();
    setupButtons(numButtons);
    add(bg);
  }

  /** This method is called from within the constructor to
   * initialize the form.
   * WARNING: Do NOT modify this code. The content of this method is
   * always regenerated by the Form Editor.
   */
  @SuppressWarnings("unchecked")
  // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
  private void initComponents() {

    setLayout(null);
  }// </editor-fold>                        
  // Variables declaration - do not modify                     
  // End of variables declaration                   

  // My variables
  private Vector<DragBarButton> theButtons = new Vector<DragBarButton>();
  private static final int DEFAULT_BUTTON_HEIGHT = 30;
  private static final String DEFAULT_BUTTON_NAME_ROOT = "";
  // The gap between buttons
  private static final int DEFAULT_GAP_SIZE = 20;
  // the gap between buttons and the left and right borders
  private static final int DEFAULT_EDGE_GAP_SIZE = 10;
  private int zeroHeight = 0;
  private DragBarBG bg = new DragBarBG();
  // scale indicates maximum absolute value of the bar numbers
  private double scale = 1.0;
  // this is value is how close to the border the buttons can get
  int borderBufferZone = 50;
  // number of decimal places for display purposes
  int numberOfDecimals = 3;
  // stores the size of buttons temporarily
  //Dimension oldSize = new Dimension(0, 0);
  // stores the old corner pt of buttons temporarily
  //Point oldCorner = new Point(0, 0);
  // indicates if a button is being pressed
  //boolean buttonPressed = false;

  // My methods
  public Vector<DragBarButton> getButtons()
  {
    return theButtons;
  }

  private void setupButtons(int numButtons)
  {
    // we divide by numButtons + 1 because we want the locations of the
    // centers of the buttons, not the length they should be
    Dimension size = getSize();
    int xIncrement = size.width / (numButtons + 1);
    int buttonWidth = size.height / numButtons;

    for (int i = 0; i < numButtons; i++)
    {
      String name = DEFAULT_BUTTON_NAME_ROOT + (i + 1);

      final DragBarButton currentB = new DragBarButton(name + ": 0");
      currentB.setName(name);
      currentB.setDoubleBuffered(true);
      int x = xIncrement * (i + 1);
      // buttons are set along the center of the panel
      int y = HEIGHT / 2;
      zeroHeight = y;

      bg.addLine(new Point(x, y));
      currentB.setLocation(x, y);
      currentB.setSize(buttonWidth, currentB.getSize().height);
      currentB.setPreferredSize(new Dimension(buttonWidth, DEFAULT_BUTTON_HEIGHT));

      currentB.addMouseMotionListener(new java.awt.event.MouseMotionAdapter()
      {

        public void mouseDragged(java.awt.event.MouseEvent evt)
        {
          buttonMouseDragged(evt, currentB);
        }
      });

      currentB.addMouseListener(new java.awt.event.MouseAdapter()
      {

        public void mouseEntered(java.awt.event.MouseEvent evt)
        {
          buttonMouseEntered(evt, currentB);
        }

        public void mouseExited(java.awt.event.MouseEvent evt)
        {
          buttonMouseExited(evt, currentB);
        }

        public void mouseReleased(java.awt.event.MouseEvent evt)
        {
          buttonMouseReleased(evt, currentB);
        }
      });


      theButtons.add(currentB);
      add(currentB);
    }
  }

  public void addNewButton(String name)
  {
    // setup the new button
    final DragBarButton newButton = new DragBarButton(name);
    newButton.setName(name);
    newButton.setDoubleBuffered(true);
    newButton.setLocation(new Point(0, HEIGHT / 2));
    newButton.addMouseMotionListener(new java.awt.event.MouseMotionAdapter()
    {

      public void mouseDragged(java.awt.event.MouseEvent evt)
      {
        buttonMouseDragged(evt, newButton);
      }
    });

    newButton.addMouseListener(new java.awt.event.MouseAdapter()
    {

      public void mouseEntered(java.awt.event.MouseEvent evt)
      {
        buttonMouseEntered(evt, newButton);
      }

      public void mouseExited(java.awt.event.MouseEvent evt)
      {
        buttonMouseExited(evt, newButton);
      }

      public void mouseReleased(java.awt.event.MouseEvent evt)
      {
        buttonMouseReleased(evt, newButton);
      }
    });
    theButtons.add(newButton);
    add(newButton, getComponentCount());

    // clear the bg
    bg.clear();
    // clear container
    this.removeAll();

    // setup vertical lines
    // placeholder, since setSize calculates actual locations.
    for (int i = 0; i < theButtons.size(); i++)
    {
      add(theButtons.get(i));
      bg.addLine(new Point(0, 0));
    }
    add(bg);

    setSize(getSize());
  }

  public void setSize(Dimension d)
  {
    super.setSize(d);
    // we divide by numButtons + 1 because we want the locations of the
    // centers of the buttons, not the length they should be
    int numButtons = theButtons.size();
    Dimension size = getSize();
    zeroHeight = size.height / 2;
    int xIncrement = size.width / (numButtons + 1);
    int totalGapUsage = (numButtons - 1) * DEFAULT_GAP_SIZE + DEFAULT_EDGE_GAP_SIZE;

    // if the panel is too small to have gaps, then just ignore them.
    if (totalGapUsage >= size.width)
    {
      totalGapUsage = 0;
    }

    int buttonWidth = (size.width - totalGapUsage) / numButtons;

    for (int i = 0; i < numButtons; i++)
    {
      JButton currentB = theButtons.get(i);
      int x = xIncrement * (i + 1);
      // buttons are set along the center of the panel
      int y = size.height / 2;
      bg.updateLineX(i, new Point(x, y));
      Point corner = getCorner(new Point(x, y), buttonWidth, DEFAULT_BUTTON_HEIGHT);
      currentB.setLocation(corner);
      currentB.setSize(buttonWidth, DEFAULT_BUTTON_HEIGHT);
      currentB.setPreferredSize(new Dimension(buttonWidth, DEFAULT_BUTTON_HEIGHT));
    }

    bg.setSize(getSize());
    int maxColorHeight = size.height / 2 - borderBufferZone;
    bg.setMaxColorHeight(maxColorHeight);
  }

  private void resetButtonLocations()
  {
    System.out.println("testing button resetting");
  }

  // returns a point representing the upper left corner of a button with
  // the input being the center of the button.
  private Point getCorner(Point center, int width, int height)
  {
    int xTranslate = width / 2;
    int yTranslate = height / 2;
    return new Point(center.x - xTranslate, center.y - yTranslate);
  }

  private void buttonMouseDragged(java.awt.event.MouseEvent evt, DragBarButton theButton)
  {
    theButton.setIsPressed(true);
    theButton.setSize(theButton.getOldSize());
    theButton.setLocation(theButton.getOldLocation());
    theButton.setIsExpanded(false);

    Point currentPt = evt.getPoint();
    Point oldPt = theButton.getOldLocation();
    int buttonHeight = theButton.getOldSize().height;
    int halfHeight = buttonHeight / 2;
    int destinationX = oldPt.x;
    int destinationY = oldPt.y + currentPt.y - halfHeight;
    // this is the maximum distance the button can move from the center based on the border buffer
    double maxDistance = (getSize().height / 2.0) - borderBufferZone;
    // these are the upper and lower y values for the buttons at their maximums
    double lowerMax = (getSize().height / 2.0) + maxDistance - (buttonHeight / 2);
    double upperMax = (getSize().height / 2.0) - maxDistance - (buttonHeight / 2);

    // if the destination is too close to the border, change it
    if (destinationY <= upperMax)
    {
      destinationY = (int) upperMax;
    } else
    {
      if (destinationY >= lowerMax)
      {
        destinationY = (int) lowerMax;
      }
    }

    // hValue is the height in relation to the zero height
    double hValue = -(destinationY + (buttonHeight / 2.0) - zeroHeight);
    // scaledValue is the actual display value
    double scaledValue = (hValue / (maxDistance)) * scale;
    theButton.setValue(scaledValue);
    double truncated = truncateDouble(scaledValue);
    Point destination = new Point(destinationX, destinationY);
    theButton.setOldLocation(destination);

    theButton.setLocation(destination);
    theButton.setText(theButton.getName() + ": " + truncated);

    int lineX = destinationX + (theButton.getOldSize().width / 2);
    int lineY = destinationY + (theButton.getOldSize().height / 2);

    // find the index value for the vertical bars
    int index = 0;
    for (int i = 0; i < theButtons.size(); i++)
    {
      if (theButtons.get(i).equals(theButton))
      {
        index = i;
      }
    }

    bg.updateLineX(index, new Point(lineX, lineY));
    bg.drawLines();

    theButton.setOldLocation(theButton.getLocation());
    theButton.setOldSize(theButton.getSize());
    theButton.setIsExpanded(true);
    zoomSize(theButton);
    repaint();

    for (int i = 0; i < theButtons.size(); i++)
    {
      theButtons.get(i).repaint();
    }
  }

  private void buttonMouseReleased(java.awt.event.MouseEvent evt, DragBarButton currentB)
  {
    if (currentB.isExpanded())
    {
      currentB.setIsPressed(false);
      currentB.setLocation(currentB.getOldLocation());
      currentB.setSize(currentB.getOldSize());
      currentB.setIsExpanded(false);
      repaint();
    }
  }

  private void buttonMouseEntered(java.awt.event.MouseEvent evt, DragBarButton currentB)
  {
    if (!currentB.isExpanded())
    {
      currentB.setOldLocation(currentB.getLocation());
      currentB.setOldSize(currentB.getSize());
      currentB.setIsExpanded(true);
      zoomSize(currentB);
      repaint();
    }
  }

  private void buttonMouseExited(java.awt.event.MouseEvent evt, DragBarButton currentB)
  {
    if (currentB.isExpanded() && !currentB.isPressed())
    {
      currentB.setLocation(currentB.getOldLocation());
      currentB.setSize(currentB.getOldSize());
      currentB.setIsExpanded(false);
      repaint();
    }
  }

  public double calculateScaledValue(JButton theButton)
  {
    // this is the maximum distance the button can move from the center based on the border buffer
    double maxDistance = (getSize().height / 2.0) - borderBufferZone;
    Point p = theButton.getLocation();
    double hValue = -(p.y + (theButton.getHeight() / 2.0) - zeroHeight);
    double retValue = (hValue / (maxDistance)) * scale;
    // This is to get rid of the stupid -0.0 display problem
    if (retValue == 0)
    {
      retValue = 0;
    }
    return retValue;
  }

  public void zoomSize(DragBarButton currentB)
  {
    double widthZoomFactor = 2;
    double heightZoomFactor = 1.2;
    Dimension d = currentB.getSize();
    Dimension newD = new Dimension((int) (d.width * widthZoomFactor), (int) (d.height * heightZoomFactor));
    int newX = currentB.getLocation().x - ((newD.width - d.width) / 2);
    int newY = currentB.getLocation().y - ((newD.height - d.height) / 2);
    Point newPt = new Point(newX, newY);

    currentB.setSize(newD);
    currentB.setLocation(newPt);
    this.setComponentZOrder(currentB, 0);
  }

  public void clearBG()
  {
    bg.clear();
  }

  public void reset()
  {
    setSize(getSize());
    bg.drawLines();
    for (int i = 0; i < theButtons.size(); i++)
    {
      DragBarButton b = theButtons.get(i);
      b.setValue(0);
      b.setText(b.getName() + ": " + b.getValue());
      b.repaint();
    }
  }

  // truncates the double for printing purposes
  private double truncateDouble(double input)
  {
    return (double) (((int) (input * Math.pow(10, numberOfDecimals))) / Math.pow(10, numberOfDecimals));
  }

  public void setScale(double newScale)
  {
    scale = newScale;
  }

  public double getScale()
  {
    return scale;
  }
}
